# iNote.py
# version: 1.3.0
import os
import re
import sys
from datetime import datetime, timedelta, date


def resolves_date_filename(file_name, start_index=0, end_index=None):
    """
    解析文件名中的日期

    :param file_name:
    :param start_index:
    :param end_index:
    :return:
    """
    date_str = os.path.splitext(file_name)[0][start_index:end_index]
    # TODO 待清理
    # print('date_str ', date_str)
    # input('暂停')
    try:
        # 尝试解析格式为% Y_%m_%d 的日期
        date_filename = datetime.strptime(date_str, '%Y_%m_%d').date()
    except ValueError:
        try:
            # 尝试解析格式为 %Y-%m-%d 的日期
            date_filename = datetime.strptime(date_str, '%Y-%m-%d').date()
        except ValueError:
            try:
                # 尝试解析格式为 %Y.%m.%d 的日期
                date_filename = datetime.strptime(date_str, '%Y.%m.%d').date()
            except ValueError:
                try:
                    # 尝试解析格式为 %Y%m%d 的日期
                    date_str_no_separator = date_str[start_index:start_index+8]
                    date_filename = datetime.strptime(date_str_no_separator, '%Y%m%d').date()
                except ValueError:
                    try:
                        # 尝试解析格式为 %Y %m %d 的日期
                        date_filename = datetime.strptime(date_str, '%Y %m %d').date()
                    except ValueError:
                        # 如果无法解析日期，跳过这个文件
                        date_filename = ''

    return date_filename


class INote:
    def __init__(self):
        # 文件扩展名
        self.file_extension = '.md'
        # 日志状态
        self.state = []
        # 日志模式
        self.mode = 0
        # 按照月份整合日志文件的字典容器
        self.month_files = {}

        # 指定工作路径 (去除两端可能含有的引号)
        try:
            self.custom_dir = sys.argv[1].strip('\'\"')
        except IndexError:
            self.custom_dir = ''

        # 获取当前目录
        self.current_dir = os.path.dirname(str(sys.argv[0]))
        # 获取上级目录
        self.parent_dir = os.path.abspath(os.path.join(self.current_dir, ".."))
        # 确定工作路径
        if os.path.exists(self.custom_dir):
            self.working_path = self.custom_dir
        else:
            self.working_path = self.parent_dir

        # 定义日期格式
        self.date_format_filename = '%Y-%m-%d'
        self.month_format_filename = '%Y-%m'
        self.date_format_secondary_header = '%Y-%m-%d'

        # 打开日志
        self.open_note()
        # 分析上级目录的日志文件的组成
        self.analysis_note()
        if self.mode == 2:
            # 模式2: 仅有昨天和今天和日志, 合并日志
            self.merge_note_file()
        elif self.mode == 3:
            # 模式3: 含有昨天之前的日志, 合并日志并排序
            self.merge_note_file()
            self.merge_same_day_notes()
            self.sort_by_date()

    def open_note(self):
        """使用默认应用打开指定目录中当日的日志文件

        无文件会自动创建
        """
        import platform

        # 定义文件日期格式和日志文件标题格式
        today_filename = datetime.now().strftime(self.date_format_filename)
        today2_secondary_header = datetime.now().strftime(self.date_format_secondary_header)
        file_name = f'{today_filename}{self.file_extension}'
        file_path = os.path.join(self.working_path, file_name)

        # 定义模板文件
        template_file_name = '__每日模板__.md'
        template_file_path = os.path.join(self.working_path, template_file_name)
        template_file_data = ''
        # 如果模板文件存在, 则读取其中内容
        if os.path.exists(template_file_path):
            with open(template_file_path, 'r') as f:
                template_file_data = f.read()
            pass

        # 检查 markdown 文件是否存在
        if not os.path.exists(file_path):
            with open(file_path, 'w') as f:
                f.write('## ' + today2_secondary_header + '\n\n')
                # 插入模板
                f.write(template_file_data)
                # print(f'已创建文件: {file_path}')

        # 根据操作系统使用不同的命令打开文件
        if platform.system() == 'Darwin':
            os.system(f'open "{file_path}"')
        elif platform.system() == 'Windows':
            os.system(f'start "" "{file_path}"')
        elif platform.system() == 'Linux':
            os.system(f'xdg-open "{file_path}"')
        else:
            print('不支持的操作系统')

    def analysis_note(self):
        """分析上级目录的日志组成, 并指定不同的工作模式

        模式1: 仅有今天和日志,
        模式2: 仅有昨天和今天和日志,
        模式3: 含有昨天之前的日志,
        """
        # 获取当前日期
        today = date.today()
        # 获取昨天的日期
        yesterday = today - timedelta(days=1)

        # 获取上级目录下的所有日志文件的文件名
        note_files = [f for f in os.listdir(self.working_path) if f.endswith(self.file_extension)]
        """ note_files 形式示例
               self.month_files = ['2022-10-07.md', '2022_10_08.md']
        """


        # 根据文件名中的日期信息，将文件名分组，得到每个月的文件名列表
        for f in note_files:
            # 解析文件名中的日期, 选取前十个字符
            date_filename = resolves_date_filename(f, 0, 10)
            # TODO 待清理
            # print(date_filename)
            # input('zaiting')
            # 记录日志组成. 如果日期大于等于今天，跳过这个文件
            if not date_filename:
                continue
            elif date_filename > today:
                continue
            elif date_filename == today:
                self.state.append('today')
                continue
            elif date_filename == yesterday:
                self.state.append('yesterday')
            elif date_filename < yesterday:
                self.state.append('earlier')

            # 定义文件名
            month_filename = date_filename.strftime(self.month_format_filename)
            if month_filename not in self.month_files:
                self.month_files[month_filename] = []
            self.month_files[month_filename].append((os.path.join(self.working_path, f), date_filename))

        """ self.month_files 形式
        self.month_files = 
        {'2022_10': [('E:\\code\\python\\idem0724\\2022 10 06.md', datetime.date(2022, 10, 6)), 
        ('E:\\code\\python\\idem0724\\2022-10-07.md', datetime.date(2022, 10, 7)), 
        ('E:\\code\\python\\idem0724\\20221009.md', datetime.date(2022, 10, 9)), 
        ('E:\\code\\python\\idem0724\\2022_10_07.md', datetime.date(2022, 10, 7))], 
        '2022_09': [('E:\\code\\python\\idem0724\\2022_09_24.md', datetime.date(2022, 9, 24)), 
        ('E:\\code\\python\\idem0724\\2022_09_25.md', datetime.date(2022, 9, 25)), 
        ('E:\\code\\python\\idem0724\\2022_09_26.md', datetime.date(2022, 9, 26))], 
        '2023_07': [('E:\\code\\python\\idem0724\\2023_07_24.md', datetime.date(2023, 7, 24)), 
        ('E:\\code\\python\\idem0724\\2023_07_26.md', datetime.date(2023, 7, 26))]}
        """

        if 'today' in self.state:
            self.mode = 1
        if 'yesterday' in self.state:
            self.mode = 2
        if 'earlier' in self.state:
            self.mode = 3

    def merge_note_file(self):
        """合并日志文件

        将上级目录中文件名为日期的日志文件, 做同月合并. 仅合并当前日期之前的日志文件.
        """

        # 对于每个月的文件名列表，按照日期顺序将文件内容读取出来，添加二级标题标注日期，然后合并为一个字符串
        for month, files in self.month_files.items():
            files_content = []
            for f, _date in sorted(files, key=lambda x: x[1]):
                with open(f, 'r', encoding='utf-8') as file:
                    content = file.read()

                    # 检查第一个非空行是否为二级标题
                    lines = content.split("\n")
                    for line in lines:
                        if line.strip() != "":
                            if not line.startswith("## "):
                                # 在文档之前添加日期的二级标题
                                date_title = f"## {_date.strftime('%Y-%m-%d')}\n\n"
                                content = date_title + content
                            break

                    # 添加 日期标题
                    files_content.append(content)

                # 读取完文件后，将文件删除
                os.remove(f)

            merged_content = '\n\n'.join(files_content)

            file_path = os.path.join(self.working_path, f'{month}{self.file_extension}')

            # 将合并后的字符串写入一个新的日志文件中，以类似于 2022_09 的形式命名
            with open(file_path, 'a', encoding='utf-8') as file:
                file.write('\n')
                file.write(merged_content)

    def merge_same_day_notes(self):
        """整合内容

        操作上级目录中的日志文件——合并日志文件中相同二级标题下的内容
        """
        for month, files in self.month_files.items():
            # 读取文件内容
            file_path = os.path.join(self.working_path, f'{month}{self.file_extension}')
            try:
                with open(file_path, "r", encoding="utf-8") as file:
                    content = file.read()
            except Exception as e:
                print(e)
                return

            # 在文档的最后一行插入一个空行
            content = content + "\n"

            # 提取 markdown 文件中的日期和内容
            pattern = r"## (\d{4}-\d{2}-\d{2})([\s\S]*?)(?=\n## \d{4}-\d{2}-\d{2}\n|$)"

            # 提取标题和内容
            matches = re.findall(pattern, content)

            # 用字典保存每个标题对应的内容
            merged_content_dict = {}
            for match in matches:
                _date = match[0]
                text = match[1]
                _date = _date.strip()
                text = text.strip()

                if _date in merged_content_dict:
                    # 内容为空不添加
                    if text == "":
                        pass
                    else:
                        merged_content_dict[_date] += "\n\n" + text
                else:
                    merged_content_dict[_date] = text

            # 生成合并后的内容
            merged_content = ""
            for _date, text in merged_content_dict.items():
                merged_content += f"## {_date}\n\n{text}\n\n"

            # 将合并后的内容写入文件
            with open(file_path, "w", encoding="utf-8") as merged_file:
                merged_file.write(merged_content)

    def sort_by_date(self):
        """日期排序

        将 markdown 中的以 %Y-%m-%d 为格式的二级标题按照从早到晚排序
        """
        for month, files in self.month_files.items():
            # 读取文件内容
            file_path = os.path.join(self.working_path, f'{month}{self.file_extension}')
            try:
                with open(file_path, "r", encoding="utf-8") as file:
                    content = file.read()
            except Exception as e:
                print(e)
                return

            # 在文档的最后一行插入一个空行
            content = content + "\n"

            # 提取 markdown 文件中日期和内容方式
            pattern = r"## (\d{4}-\d{2}-\d{2})([\s\S]*?)(?=\n## \d{4}-\d{2}-\d{2}\n|$)"

            matches = re.findall(pattern, content)
            """matches 示例格式
                matches =
                [('2022-10-06', '\n\n\n'), 
                ('2022-10-08', '\n\n正文\n-\n'), 
                ('2022-10-09', '\n\n正文\n')]
            """

            # 按日期排序
            sorted_matches = sorted(matches, key=lambda x: x[0])

            # 生成排序后的内容
            sorted_content = ""
            for match in sorted_matches:
                _date = match[0]
                text = match[1]
                _date = _date.strip()
                text = text.strip()
                sorted_content += f"## {_date}\n\n{text}\n\n"

            # 将排序后的内容写入文件
            with open(file_path, "w", encoding="utf-8") as sorted_file:
                sorted_file.write(sorted_content)

if __name__ == '__main__':
    from logger import logger

    try:
        i_note = INote()
        del i_note
    except Exception as e:
        logger.warning(e)
